// Copyright 2021 Tencent. All rights reserved.
// Author: billbai <billbai@tencent.com>

// NOTE: This File Should be self contained, and cannot include other file.

#ifndef OCSENGINE_RFIX_RFIXANNOTATIONS_H_
#define OCSENGINE_RFIX_RFIXANNOTATIONS_H_

// Util Macro
#define RFIX_TOKEN_STR_(x) #x
#define RFIX_TOKEN_STR(x) RFIX_TOKEN_STR_(x)

#define RFIX_TOKEN_CONCATE_(x, y) x ## y
#define RFIX_TOKEN_CONCATE(x, y) RFIX_TOKEN_CONCATE_(x, y)

//
// Annotations for RFIX Patch Creator
// 以下宏用于标注需要使用 RFIX 生成补丁的代码
// 注意：以下标记宏请添加到 .m 文件 （.h 文件不会被 RFIX.app 自动识别）
//

// RFIX Annotation

// OCS 编译器（RFIX.app）会定义 __OCS_COMPILER__ 宏，
// 可以用该宏判断当前编译器是否为 RFIX/OCS
#if __OCS_COMPILER__

// 添加在 @interface 或 @implementation 之前，用于标记动态类
// 注意：添加在 class extension 之前无效
#ifndef RFIX_ADD_CLASS
#define RFIX_ADD_CLASS() __attribute__((annotate("@RFIX_ADD_CLASS@")))
#endif

// 添加在 @protocol 之前，用于标记动态 protocol
#ifndef RFIX_ADD_PROTOCOL
#define RFIX_ADD_PROTOCOL() __attribute__((annotate("@RFIX_ADD_PROTOCOL@")))
#endif

// 添加在 @implementation 中的方法名*之后*，用于标记替换或添加方法
#ifndef RFIX_METHOD
#define RFIX_METHOD() __attribute__((annotate("@RFIX_METHOD@")))
#endif

// RFIX_ADD_METHOD 和 RFIX_REPLACE_METHOD 完全等价于 RFIX_METHOD,
// 仅用于更好的表达 代码编写者的意图，可以任意互换使用. 同 RFIX_METHOD()
#ifndef RFIX_ADD_METHOD
#define RFIX_ADD_METHOD() __attribute__((annotate("@RFIX_ADD_METHOD@")))
#endif
// 同 RFIX_METHOD
#ifndef RFIX_REPLACE_METHOD
#define RFIX_REPLACE_METHOD() __attribute__((annotate("@RFIX_REPLACE_METHOD@")))
#endif

// For Swift Patch
// 添加在 @implementation 之前，用于标记 Swift 补丁
#define RFIX_PATCH_SWIFT_CLASS(_cls)                               \
  static _cls* const __attribute__((                               \
      unused, annotate("@RFIX_SWIFT_DUMMY@"),                      \
      annotate("@RFIX_SWIFT_DUMMY_ID=" RFIX_TOKEN_STR(__LINE__)))) \
  RFIX_TOKEN_CONCATE(dummy_, __LINE__) = nil;                      \
  __attribute__((annotate("@RFIX_PATCH_SWIFT_CLASS@"),             \
                 annotate("@RFIX_SWIFT_DUMMY_ID=" RFIX_TOKEN_STR(__LINE__))))

// 用于标记 NSProxy 子类的补丁，
// 或者重写了关键 ObjC 消息发送相关方法的类的补丁（例如 methodSignatureForSelector，class 等等）
#ifndef RFIX_ALLOW_DANGER_PATCH
#define RFIX_ALLOW_DANGER_PATCH() __attribute__((annotate("@RFIX_ALLOW_DANGER@")))
#endif

#else  // __OCS_COMPILER__
// 非 RFIX/OCS 编译器情况下，标记宏展开为空代码，

// 添加在 @interface 或 @implementation 之前，用于标记动态类
#ifndef RFIX_ADD_CLASS
#define RFIX_ADD_CLASS()
#endif

// 添加在 @protocol 之前，用于标记动态 protocol
#ifndef RFIX_ADD_PROTOCOL
#define RFIX_ADD_PROTOCOL()
#endif

// 添加在 @implementation 中的方法名*之后*，用于标记替换或添加方法
#ifndef RFIX_METHOD
#define RFIX_METHOD()
#endif
// 同 RFIX_METHOD
#ifndef RFIX_ADD_METHOD
#define RFIX_ADD_METHOD()
#endif
// 同 RFIX_METHOD
#ifndef RFIX_REPLACE_METHOD
#define RFIX_REPLACE_METHOD()
#endif

// For Swift Patch
// 添加在 @implementation 之前，用于标记 Swift 补丁
#define RFIX_PATCH_SWIFT_CLASS(_cls)

#ifndef RFIX_ALLOW_DANGER_PATCH
#define RFIX_ALLOW_DANGER_PATCH()
#endif

#endif  // __OCS_COMPILER__


// -----------------------------------------------------------------------------
// Legacy OCS/RFIX Annotation Macro
// 以下宏标记仅用于兼容老版本 OCS/RFIX，属于被 DEPRECATED 的代码，
// 尽可能使用上面新的 RFIX Annotation.

#if __OCS_COMPILER__

//
// 标记需要被 RFIX 编译为补丁的 ObjC Method
// 用于使用 RFIX 替换类中的部分方法
#define RFIX_METHODS_START          \
    -(void)OCS_PluginMethodsStart { \
    }

#define RFIX_METHODS_END         \
    -(void)ocsPluginMethodsEnd { \
    }
//
// e.g.
// @implementation FooBar
// // method1 不在 RFIX_METHODS_START/END 之间，不会被 RFIX 编译为补丁
// - (void)method1;
//
// // RFIX_METHODS_START/END 宏之间的方法会被 RFIX 编译为补丁
// // method2 和 method3 会被 RFIX 编译为补丁
// RFIX_METHODS_START
// - (void)method2;
// - (void)method3;
// RFIX_METHODS_END
//
// // method4 不在 RFIX_METHODS_START/END 之间，不会被 RFIX 编译为补丁
// - (void)method4;
// @end

//
// 使用 RFIX 编译整个 ObjC 类
// 用于使用 RFIX 动态添加新的类
#define RFIX_CLASS_DYNAMIC_FLAG            \
    -(void)OCS_CLASS_DYNAMIC_METHOD_FLAG { \
    }
//
// e.g.
// @interface FooBar : NSObject
// @property (copy) NSString *xxx1;
// @property (strong) NSString *xxx2;
// - (void)method1;
// - (void)method2;
// @end
//
// @implementation FooBar
// // 在类的实现中加上 RFIX_CLASS_DYNAMIC_FLAG 宏，RFIX 会将整个类编译到补丁中 （包含 property/ivar/methods）
// RFIX_CLASS_DYNAMIC_FLAG
// - (void)method1 {}
// - (vooid)method2 {}
// @end

//
// 使用 RFIX 编译整个 ObjC Protocol
// 用于使用 RFIX 动态添加新的 Protocol
#define RFIX_PROTOCOL_DYNAMIC_FLAG \
    @optional                      \
    -(void)OCS_PROTOCOL_DYNAMIC_METHOD_FLAG;
//
// e.g.
// @protocol FooBarProtocol
// // 在 protocol 中添加 RFIX_PROTOCOL_DYNAMIC_FLAG 宏，RFIX 回将整个 protocol 编译到补丁中
// RFIX_PROTOCOL_DYNAMIC_FLAG
// 注意 RFIX_PROTOCOL_DYNAMIC_FLAG 会展开一个 @optional
//
// @required
// - (void)protocolMethod1;
// @optional
// - (void)protocolMethod2;
// @end

#else

#define RFIX_METHODS_START
#define RFIX_METHODS_END
#define RFIX_CLASS_DYNAMIC_FLAG
#define RFIX_PROTOCOL_DYNAMIC_FLAG

#endif  // __OCS_COMPILER__

#endif  // OCSENGINE_RFIX_RFIXANNOTATIONS_H_
